package org.jeecg.modules.system.controller.login;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.Limit;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.controller.login.constant.Prompt;
import org.jeecg.modules.system.controller.login.model.OriginalSmsLoginModel;
import org.jeecg.common.message.UnicomSmsUtil;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysDictService;
import org.jeecg.modules.system.service.ISysTenantService;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * 短信登录
 *
 * @author tianyi.jiang
 * @since 1.0.0
 */
@RestController
@RequestMapping("/sys")
@ConditionalOnExpression("'${basicplatform.login.sms.enable:false}'.equals('true')")
public class SmsLoginHandler extends LoginHandler {

    /**
     * 发送短信验证码
     * 1.验证图形验证码
     * 2.对入参"电话号码"字段(RSA加密)解密
     * 3.判定电话号码是否发送过，短信验证码10分钟内有效
     * 4.发送验证码短信
     *
     * @param originalSmsLoginModel {@link OriginalSmsLoginModel}
     * @author jiangtianyi
     * @since 1.0
     */
    @PostMapping(value = "/sms")
    public Result<?> sendSmsCode(@RequestBody @Valid OriginalSmsLoginModel originalSmsLoginModel) {
        String lowerCaseCaptcha = originalSmsLoginModel.getCaptcha().toLowerCase();
        // 生成图形验证码Redis Key
        String captchaRedisKey = this.generateGraphicCodeRedisKey(lowerCaseCaptcha, originalSmsLoginModel.getCheckKey());
        // 校验图形验证码
        if (this.verifyGraphicCode(captchaRedisKey, lowerCaseCaptcha)) {
            return Result.error(HttpStatus.PRECONDITION_FAILED.value(), Prompt.GRAPHIC_CODE_WRONG_PROMPT);
        }
        // 暗文手机号码解密
        String mobile = rsaEncryptProperty.decrypt(originalSmsLoginModel.getMobile());
        SysUser sysUser = sysUserService.getUserByPhone(mobile);
        // 校验用户是否有效
        Result<?> result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }
        return doSendSmsCode(mobile);
    }

    /**
     * 接口限制：5 次/分钟 {@link Limit}
     * 手机号码登录接口
     * 1.入参电话号码(RSA加密)解密
     * 2.校验输入的短信验证码正确性
     * 3.校验用户有效性
     * 4.登录成功后，删除短信验证码
     *
     * @author jiangtianyi
     * @since 1.0
     */
    @Limit(value = 5)
    @PostMapping("/phoneLogin")
    public Result<?> loginBySmsCode(@RequestBody @Valid OriginalSmsLoginModel originalSmsLoginModel) {
        return this.doSmsCodeLogin(originalSmsLoginModel.getMobile(), originalSmsLoginModel.getCaptcha());
    }

    /**
     * 执行短信验证码登录
     *
     * @param encryptMobile RSA加密后的手机号码
     * @param captcha       短信验证码（输入）
     * @author jiangtianyi
     * @since 1.0
     */
    public Result<?> doSmsCodeLogin(String encryptMobile, String captcha) {
        // 暗文手机号码解密
        String mobile = rsaEncryptProperty.decrypt(encryptMobile);
        // 校验短信验证码
        String verifyMessage = this.verifySmsCode(mobile, captcha);
        if (StringUtils.isNotEmpty(verifyMessage)) {
            return Result.error(verifyMessage);
        }
        SysUser sysUser = sysUserService.getUserByPhone(mobile);
        // 校验用户是否有效
        Result<?> result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }
        // 登录成功后删除短信验证码
        redisUtil.del(this.generateSmsCodeRedisKey(mobile));
        // 执行登录逻辑
        return this.doLogin(sysUser);
    }

    /**
     * 校验短信验证码
     *
     * @param mobile  明文手机号码
     * @param smsCode 短信验证码（前端输入）
     * @return 示例：
     * 1.Redis中无短信验证码时，提示重新获取短信验证码；
     * 2.短信验证码不匹配时，提示短信验证错误；
     * 3.匹配成功时，返回null
     * @author jiangtianyi
     * @since 1.0
     */
    private String verifySmsCode(String mobile, String smsCode) {
        // 生成短信验证码Redis Key
        String captchaRedisKey = this.generateSmsCodeRedisKey(mobile);
        Object redisSmsCode = redisUtil.get(captchaRedisKey);
        // Redis中无短信验证码时，提示获取短信验证码
        if (redisSmsCode == null) {
            return Prompt.SMS_CODE_NULL_IN_REDIS_PROMPT;
        } else if (!String.valueOf(redisSmsCode).equalsIgnoreCase(smsCode)) {
            return Prompt.SMS_CODE_WRONG_PROMPT;
        }
        return null;
    }

    public SmsLoginHandler(RedisUtil redisUtil, UnicomSmsUtil unicomSmsUtil, RsaEncryptProperty rsaEncryptProperty, BaseCommonService baseCommonService, ISysDictService sysDictService, ISysTenantService sysTenantService, ISysUserService sysUserService, ISysDepartService sysDepartService, RedisTemplate<String, Object> redisTemplate) {
        super(redisUtil, unicomSmsUtil, rsaEncryptProperty, baseCommonService, sysDictService, sysTenantService, sysUserService, sysDepartService, redisTemplate);
    }
}
